/********************************************************************************
  * @file    waveprocess.cpp
  * @author  Lun Li
  * @version V2.2.0
  * @date    2022.7.8
  * @brief   This file provides all the WaveProcess functions.
  *******************************************************************************/

#include "waveprocess.h"

WaveProcess::WaveProcess(const ProgramConfig *config, QObject *parent)
    : QProcess(parent),
      m_config(config)
{
    connect(this, &QProcess::errorOccurred, this, [=]() {
        emit waveError(errorString());
    });
    connect(this, &QProcess::readyReadStandardError, this, [=](){
        emit waveError(QString::fromLocal8Bit(readAllStandardError()));
    });
    connect(this, &QProcess::readyReadStandardOutput, this, [=](){
        emit waveOutput(QString::fromLocal8Bit(readAllStandardOutput()));
    });
    connect(this, &WaveProcess::waveStarted, this, [=]() {
        m_isStarted = true;
    });
    connect(this, &QProcess::finished, this, [=]() {
        emit waveFinished();
        m_isStarted = false;
        inputStream.flush();
        outputStream.flush();
    });
    connect(this, &WaveProcess::waveInput, this, [&](const QString &input) {
        if (m_isLogEnabled) {
            inputStream << input << "\r\n";
            outputStream << input << "\r\n";
        }
    });
    connect(this, &WaveProcess::waveOutput, this, [&](const QString &output) {
        if (m_isLogEnabled) {
            outputStream << output << "\r\n";
        }
    });
    connect(this, &WaveProcess::waveError, this, [&](const QString &error) {
        if (m_isLogEnabled) {
            outputStream << error << "\r\n";
        }
    });
    connect(m_config, &ProgramConfig::toolConfigChanged, this, [&] {
        m_isLogEnabled = m_config->isLogEnabled();
    });

    extern SignalConnection globalSignal;
    connect(&globalSignal, &SignalConnection::showWaveRequested, this, &WaveProcess::runCommand);
    connect(&globalSignal, &SignalConnection::addWaveCommandRequested, this, &WaveProcess::addCommand);
    connect(this, &WaveProcess::waveInput, &globalSignal, &SignalConnection::waveInput);
    connect(this, &WaveProcess::waveOutput, &globalSignal, &SignalConnection::waveOutput);
    connect(this, &WaveProcess::waveError, &globalSignal, &SignalConnection::waveError);

    inputStream.setDevice(&inputLog);
    inputStream.setEncoding(QStringConverter::Utf8);
    outputStream.setDevice(&outputLog);
    outputStream.setEncoding(QStringConverter::Utf8);
    m_isLogEnabled = m_config->isLogEnabled();
}

WaveProcess::~WaveProcess()
{
    closeLog();
}

void WaveProcess::setWorkingDirectory(const QString &dir)
{
    closeLog();
    inputLog.setFileName(dir + "/waveInput.log");
    outputLog.setFileName(dir + "/waveOutput.log");
    openLog();
    QProcess::setWorkingDirectory(dir);
}

void WaveProcess::runCommand(const QString &command)
{
    if (m_isStarted) {
        return;
    }
    emit waveStarted();
    emit waveInput(command);
    startCommand(command);
    m_isStarted = waitForStarted();
    waitForReadyRead();
}

void WaveProcess::addCommand(const QString &command)
{
    if (!m_isStarted) {
        runCommand(command);
    } else {        
        emit waveInput(command);
        write((command + "\r\n").toStdString().c_str());
        waitForBytesWritten();
    }
}

void WaveProcess::openLog()
{
    if (!inputLog.isOpen()) {
        inputLog.open(QFile::WriteOnly | QFile::Truncate);
    }
    if (!outputLog.isOpen()) {
        outputLog.open(QFile::WriteOnly | QFile::Truncate);
    }
}

void WaveProcess::closeLog()
{
    if (inputLog.isOpen()) {
        inputLog.close();
    }
    if (outputLog.isOpen()) {
        outputLog.close();
    }
}
